use crate::mm::{MemorySet, MapPermission, PhysPageNum, KERNEL_SPACE, VirtAddr};
use crate::trap::{TrapContext, trap_handler};
use crate::config::{TRAP_CONTEXT, INIT_PRORITY, BIG_STRIDE, kernel_stack_position};

use super::TaskContext;

#[derive(Copy, Clone, PartialEq)]
pub enum TaskStatus {
    UnInit, // 未初始化
    Ready,  // 已初始化, 未运行
    Running,// 运行中
    Exited, // 已退出
}

use core::{cmp::Ordering, marker::Copy};

pub struct TaskControlBlock { // 用于管理一个 Task 的状态
    pub task_ctx_ptr: usize,
    pub task_status: TaskStatus,
    pub priority: isize,
    pub stride: isize,
    pub pass: isize,
    pub memory_set: MemorySet,
    pub trap_ctx_ppn: PhysPageNum,
    pub base_size: usize, // 统计了应用数据的大小，
                          // 也就是 在应用地址空间中从 0x0 开始到用户栈结束一共包含多少字节
}

impl PartialEq for TaskControlBlock {
    fn eq(&self, other: &Self) -> bool {
        self.pass == other.pass
    }
}

impl Eq for TaskControlBlock {}

impl PartialOrd for TaskControlBlock {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.pass.partial_cmp(&other.pass).map(|order| order.reverse())
    }
}

impl Ord for TaskControlBlock {
    fn cmp(&self, other: &Self) -> Ordering {
        self.pass.cmp(&other.pass).reverse()
    }
}

impl TaskControlBlock {
    pub fn get_task_ctx_ptr2(&self) -> *const usize {
        &self.task_ctx_ptr as *const usize
    }
}

impl TaskControlBlock {
    pub fn new(elf_data: &[u8], app_id: usize) -> Self {
        // memory_set with elf program headers/trampoline/trap context/user stack
        let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data);
        let trap_ctx_ppn = memory_set
            .translate(VirtAddr::from(TRAP_CONTEXT).into())
            .unwrap()
            .ppn();
        let task_status = TaskStatus::Ready;
        // map a kernel-stack in kernel space
        let (kernel_stack_bottom, kernel_stack_top) = kernel_stack_position(app_id);
        KERNEL_SPACE
            .lock()
            .insert_framed_area(
                kernel_stack_bottom.into(),
                kernel_stack_top.into(),
                MapPermission::R | MapPermission::W,
            );

        let task_ctx_ptr = (kernel_stack_top - core::mem::size_of::<TaskContext>())
            as *mut TaskContext;
        unsafe { *task_ctx_ptr = TaskContext::goto_trap_return(); }
        let task_control_block = Self {
            task_ctx_ptr: task_ctx_ptr as usize,
            task_status,
            priority: INIT_PRORITY,
            stride: BIG_STRIDE / INIT_PRORITY,
            pass: BIG_STRIDE / INIT_PRORITY,
            memory_set,
            trap_ctx_ppn,
            base_size: user_sp,
        };

        // prepare TrapContext in user space

        let trap_ctx = task_control_block.get_trap_ctx();
        *trap_ctx = TrapContext::app_init_context(
            entry_point,
            user_sp,
            KERNEL_SPACE.lock().token(),
            kernel_stack_top,
            trap_handler as usize,
        );
        task_control_block
    }

    pub fn get_user_token(&self) -> usize {
        self.memory_set.token()
    }

    pub fn get_trap_ctx(&self) -> &'static mut TrapContext {
        self.trap_ctx_ppn.get_mut()
    }

    pub fn get_task_cx_ptr2(&self) -> *const usize {
        &self.task_ctx_ptr as *const usize
    }
}
